#include "Gencpp_Ga.h"


Gencpp_Ga::Gencpp_Ga(void)
{
	mi_SizePopulation = SIZE_POPULATION;
	mf_bestFitness = 0.f;
}

Gencpp_Ga::~Gencpp_Ga(void)
{

}

void Gencpp_Ga::run(void)
{
	int count_generation = 0;

	initialisePopulation();
	evaluateFitness();

	while ( count_generation < MAX_GENERATION)
	{
		selectParents();
		evaluateFitness();
		count_generation++;
		
		printf("Generation %i\n",count_generation);
		displayPopulation();
	}
}

void Gencpp_Ga::renderPopulation(void)
{

}

void Gencpp_Ga::displayPopulation(void)
{
	for (int i=0;i<mi_SizePopulation-1;i++)
	{
		printf("Indiv %i : [",i);
		for(int j=0;j<SIZE_GENOTYPE;j++)
		{
			printf("%i,",ma_Population[i]->ma_Genotype[j]);
		}	
		if(ma_Population[i]->getFitness() > mf_bestFitness)
		{
			mf_bestFitness = ma_Population[i]->getFitness();
			printf("	Best Fitness = %f\n",mf_bestFitness);
		}
	}
	
}

void Gencpp_Ga::initialisePopulation(void)
{
	for(int i=0;i<mi_SizePopulation;i++)
	{
		Gencpp_Individual* gindiv = new Gencpp_Individual;
		gindiv->createRandomGenotype();
		gindiv->computeColor();

		ma_Population.push_back(gindiv);

	}
}

void Gencpp_Ga::selectParents(void)
{
	srand(time(NULL));
	int indexParent1 = rand()%mi_SizePopulation;
	int indexParent2 = rand()%mi_SizePopulation;
	int indexParent3 = rand()%mi_SizePopulation;

	while(indexParent1 == indexParent2 ||
		indexParent2 == indexParent3 ||
		indexParent1 == indexParent3)
	{
		indexParent1 = rand()%mi_SizePopulation;
		indexParent2 = rand()%mi_SizePopulation;
		indexParent3 = rand()%mi_SizePopulation;
	}

	if(ma_Population[indexParent1]->getFitness() >= ma_Population[indexParent2]->getFitness() && ma_Population[indexParent2]->getFitness() >= ma_Population[indexParent3]->getFitness())
	{
		crossover(indexParent1,indexParent2);
		mutation(indexParent1);
	}	
	if(ma_Population[indexParent1]->getFitness() >= ma_Population[indexParent3]->getFitness() && ma_Population[indexParent3]->getFitness() >= ma_Population[indexParent2]->getFitness())
	{
		crossover(indexParent1,indexParent3);
		mutation(indexParent1);
	}		
	if(ma_Population[indexParent2]->getFitness() >= ma_Population[indexParent1]->getFitness() && ma_Population[indexParent1]->getFitness() >= ma_Population[indexParent3]->getFitness())
	{
		crossover(indexParent2,indexParent1);
		mutation(indexParent2);
	}		
	if(ma_Population[indexParent2]->getFitness() >= ma_Population[indexParent3]->getFitness() && ma_Population[indexParent3]->getFitness() >= ma_Population[indexParent1]->getFitness())
	{
		crossover(indexParent2,indexParent3);
		mutation(indexParent2);
	}		
	if(ma_Population[indexParent3]->getFitness()>= ma_Population[indexParent1]->getFitness() && ma_Population[indexParent1]->getFitness() >= ma_Population[indexParent2]->getFitness())
	{
		crossover(indexParent3,indexParent1);
		mutation(indexParent3);
	}		
	if(ma_Population[indexParent3]->getFitness() >= ma_Population[indexParent2]->getFitness() && ma_Population[indexParent2]->getFitness() >= ma_Population[indexParent1]->getFitness())
	{
		crossover(indexParent3,indexParent2);
		mutation(indexParent3);
	}

	
}

void Gencpp_Ga::mutation(int _iparent)
{
	if (rand()/RAND_MAX < MUTATION_RATE)
	{
		int change_bit = rand()%SIZE_GENOTYPE;

		if(ma_Population[_iparent]->ma_Genotype[change_bit] == 1)
			ma_Population[_iparent]->ma_Genotype[change_bit] == 0;
		else
			ma_Population[_iparent]->ma_Genotype[change_bit] == 1;
	}
}

void Gencpp_Ga::crossover(int _iparent1, int _iparent2)
{
	if (rand()/RAND_MAX < CROSSOVER_RATE)
	{
		int crossover_point = rand()%SIZE_GENOTYPE;
		
		std::vector<int> temp;

		for( int i=0;i<crossover_point;i++)
		{
			temp.push_back(ma_Population[_iparent1]->ma_Genotype[i]);
			ma_Population[_iparent1]->ma_Genotype[i] = ma_Population[_iparent2]->ma_Genotype[i];
			ma_Population[_iparent2]->ma_Genotype[i] = temp[i];
		}
	}

}

void Gencpp_Ga::evaluateFitness(void)
{
	for (int i=0;i< mi_SizePopulation;i++)
	{
		ma_Population[i]->setFitness(0.0);

		for(int j=0;j<SIZE_GENOTYPE;j++)
		{
			if(ma_Population[i]->ma_Genotype[j] == 1)
				ma_Population[i]->setFitness( ma_Population[i]->getFitness() + 1.0/SIZE_GENOTYPE);
		}
	}
}